﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WMM.Tapioca.Formula;
using System.Xml.Linq;
using WMM.Tapioca.Linkbase;

namespace WMM.Tapioca.Taxonomy
{
    public class DTSFormula
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private DTS dts;

        private Dictionary<string, string> namespaces;

        public Dictionary<string, string> Namespaces
        {
            get { return namespaces; }
            set { namespaces = value; }
        }

        List<ValueAssertion> valueAssertions;

        public List<ValueAssertion> ValueAssertions
        {
            get { return valueAssertions; }
            set { valueAssertions = value; }
        }

        List<ExistenceAssertion> existenceAssertions;

        public List<ExistenceAssertion> ExistenceAssertions
        {
            get { return existenceAssertions; }
            set { existenceAssertions = value; }
        }

        List<ConsistencyAssertion> consistencyAssertions;

        public List<ConsistencyAssertion> ConsistencyAssertions
        {
            get { return consistencyAssertions; }
            set { consistencyAssertions = value; }
        }

        List<AssertionSet> assertionSets;

        public List<AssertionSet> AssertionSets
        {
            get { return assertionSets; }
            set { assertionSets = value; }
        }

        List<FormulaXBRL> formulas;

        public List<FormulaXBRL> Formulas
        {
            get { return formulas; }
            set { formulas = value; }
        }        


        /// <summary>
        /// The constructor.
        /// </summary>
        public DTSFormula(DTS dtsXbrl)
        {
            Controller.Instance.RaiseModelChange(this, new ModelChangeEventArgs("Building DTSFormula..."));

            dts = dtsXbrl;
            valueAssertions = new List<ValueAssertion>();
            existenceAssertions = new List<ExistenceAssertion>();
            consistencyAssertions = new List<ConsistencyAssertion>();
            assertionSets = new List<AssertionSet>();
            formulas = new List<FormulaXBRL>();
            namespaces = new Dictionary<string, string>();

            BuildFormulaLinkbase();
        }


        private void BuildFormulaLinkbase()
        {
            foreach (LinkbaseDocument linkbase in dts.LinkbaseDocuments)
            {
                if (linkbase.NamespaceManager.HasNamespace("variable"))
                {
                    GetNamespaces(linkbase);
                    BuildFormulaLinkbase(linkbase);                    
                }
            }
        }


        private void BuildFormulaLinkbase(LinkbaseDocument linkbase)
        {
            foreach (ExtendedLink extendedLink in linkbase.ExtendedLinks)
            {
                if (HasResource(extendedLink.Resources, "assertionSet"))
                {
                    assertionSets.Add(BuildAssertionSet(extendedLink));
                    continue;
                }

                if (HasResource(extendedLink.Resources, "valueAssertion"))
                {
                    valueAssertions.AddRange(BuildValueAssertion(extendedLink));
                    //continue;
                }

                if (HasResource(extendedLink.Resources, "existenceAssertion"))
                {
                    existenceAssertions.AddRange(BuildExistenceAssertion(extendedLink));
                    //continue;
                }

                if (HasResource(extendedLink.Resources, "consistencyAssertion"))
                {
                    consistencyAssertions.AddRange(BuildConsistencyAssertion(extendedLink));
                    continue;
                }                

                if (HasResource(extendedLink.Resources, "formula"))
                {
                    formulas.AddRange(BuildFormula(extendedLink));
                    //continue;
                }
            }
        }


        private bool HasResource(List<Resource> resources, string assertionName)
        {
            foreach (Resource resource in resources)
            {
                if (resource.LocalName.Equals(assertionName))
                {
                    return true;
                }
            }

            return false;
        }


        private List<ValueAssertion> BuildValueAssertion(ExtendedLink extendedLink)
        {
            List<ValueAssertion> valueAssertionsTemp = new List<ValueAssertion>();

            foreach (Resource resource in extendedLink.Resources)
            {
                if (resource.LocalName.Equals("valueAssertion"))
                {
                    valueAssertionsTemp.Add(new ValueAssertion(resource, namespaces));
                }
            }

            return valueAssertionsTemp;
        }


        private List<ExistenceAssertion> BuildExistenceAssertion(ExtendedLink extendedLink)
        {
            List<ExistenceAssertion> existenceAssertionsTemp = new List<ExistenceAssertion>();

            foreach (Resource resource in extendedLink.Resources)
            {
                if (resource.LocalName.Equals("existenceAssertion"))
                {
                    existenceAssertionsTemp.Add(new ExistenceAssertion(resource, namespaces));
                }
            }

            return existenceAssertionsTemp;
        }


        private List<ConsistencyAssertion> BuildConsistencyAssertion(ExtendedLink extendedLink)
        {
            List<ConsistencyAssertion> consistencyAssertionsTemp = new List<ConsistencyAssertion>();

            foreach (Resource resource in extendedLink.Resources)
            {
                if (resource.LocalName.Equals("consistencyAssertion"))
                {
                    consistencyAssertionsTemp.Add(new ConsistencyAssertion(resource, namespaces));
                }
            }

            return consistencyAssertionsTemp;
        }



        private AssertionSet BuildAssertionSet(ExtendedLink extendedLink)
        {
            AssertionSet assertionSet = null;

            foreach (Resource resource in extendedLink.Resources)
            {
                if (resource.LocalName.Equals("assertionSet"))
                {
                    assertionSet = new AssertionSet(resource, namespaces);
                }
            }

            return assertionSet;
        }



        private List<FormulaXBRL> BuildFormula(ExtendedLink extendedLink)
        {
            List<FormulaXBRL> formulas = new List<FormulaXBRL>();

            foreach (Resource resource in extendedLink.Resources)
            {
                if (resource.LocalName.Equals("formula"))
                {
                    formulas.Add(new FormulaXBRL(resource, extendedLink.ParentDocument, namespaces));
                }
            }

            return formulas;
        }


        private void GetNamespaces(LinkbaseDocument linkbase)
        {
            foreach (XAttribute a in linkbase.ThisXDocument.Root.Attributes())
            {
                if (a.IsNamespaceDeclaration)
                {
                    if (!namespaces.ContainsKey(a.Name.LocalName))
                    {
                        namespaces.Add(a.Name.LocalName, a.Value);
                    }
                }
            }
        }

    }
}
